# app.py
from flask import Flask, request, render_template, jsonify, send_file, url_for, session
import os
from werkzeug.utils import secure_filename
import subprocess
import traceback
from GLMService import GLMService 
import uuid
import secrets

app = Flask(__name__)

# 生成一个随机的32字节密钥
app.secret_key = secrets.token_bytes(32)

# 创建一个全局的 GLMService 实例，这样可以在所有请求之间共享会话历史
glm_service = GLMService()

# 配置上传文件夹
app.config['UPLOAD_FOLDER'] = '/app/uploads'
app.config['ALLOWED_EXTENSIONS'] = {'py'}

# 确保 uploads 文件夹存在
if not os.path.exists(app.config['UPLOAD_FOLDER']):
    os.makedirs(app.config['UPLOAD_FOLDER'])

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS']

@app.route('/chat', methods=['POST'])
def chat():
    try:
        data = request.json
        message = data.get('message')
        
        if not message:
            return jsonify({'error': 'No message provided'}), 400

        # 获取或创建会话ID
        conversation_id = session.get('conversation_id')
        if not conversation_id:
            conversation_id = str(uuid.uuid4())
            session['conversation_id'] = conversation_id
            app.logger.info(f"Created new conversation with ID: {conversation_id}")
        
        # 使用全局 GLMService 实例处理聊天消息
        response = glm_service.chat(message, conversation_id)
        
        return jsonify({
            'response': response,
            'conversation_id': conversation_id
        })
    except Exception as e:
        app.logger.error(f"Error in chat endpoint: {str(e)}\n{traceback.format_exc()}")
        return jsonify({'error': 'An error occurred processing your message'}), 500

@app.route('/clear-chat', methods=['POST'])
def clear_chat():
    try:
        conversation_id = session.get('conversation_id')
        if conversation_id:
            success = glm_service.clear_conversation(conversation_id)
            if success:
                return jsonify({'message': 'Conversation cleared successfully'})
        return jsonify({'error': 'Unable to clear conversation'}), 400
    except Exception as e:
        app.logger.error(f"Error clearing chat: {str(e)}\n{traceback.format_exc()}")
        return jsonify({'error': 'An error occurred clearing the conversation'}), 500

@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        try:
            test_requirements = request.form.get('test_requirements')
            if 'code_file' not in request.files:
                return jsonify({'error': 'No file uploaded'}), 400
                
            code_file = request.files['code_file']
            if not code_file or not allowed_file(code_file.filename):
                return jsonify({'error': 'Invalid file type'}), 400

            filename = secure_filename(code_file.filename)
            file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
            code_file.save(file_path)
            
            module_name = os.path.splitext(filename)[0]

            # 生成测试用例文件
            test_cases = generate_test_cases(test_requirements, file_path, module_name)
            test_case_file_path = create_test_case_file(test_cases, file_path)

            # 运行测试并获取结果
            coverage_report, test_output = run_pytest_and_generate_coverage(test_case_file_path)
            
            # 准备响应数据
            download_url = url_for('download_test_cases', filename=os.path.basename(test_case_file_path))
            return render_template('index.html', 
                                coverage_report=coverage_report,
                                test_output=test_output,
                                download_url=download_url)

        except Exception as e:
            error_trace = traceback.format_exc()
            app.logger.error(f"Error processing request: {error_trace}")
            return jsonify({
                'error': 'An error occurred while processing your request',
                'message': str(e),
                'details': error_trace
            }), 500

    return render_template('index.html')

@app.route('/download/<filename>')
def download_test_cases(filename):
    try:
        file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
        if not os.path.exists(file_path):
            return jsonify({'error': 'File not found'}), 404
        return send_file(file_path, as_attachment=True)
    except Exception as e:
        return jsonify({'error': 'Error downloading file', 'message': str(e)}), 500

def generate_test_cases(test_requirements, file_path, module_name):
    try:
        with open(file_path, 'r') as f:
            code_content = f.read()
            
        test_cases = glm_service.generate_test_cases(code_content, test_requirements, module_name)
        
        if not test_cases:
            raise ValueError("No test cases were generated")
            
        return test_cases
    except Exception as e:
        app.logger.error(f"Error generating test cases: {str(e)}")
        raise

def create_test_case_file(test_cases, file_path):
    try:
        test_case_file_name = 'test_' + os.path.basename(file_path)
        test_case_file_path = os.path.join(app.config['UPLOAD_FOLDER'], test_case_file_name)
        
        with open(test_case_file_path, 'w') as file:
            file.write('\n'.join(test_cases))
        
        app.logger.info(f"Generated test case file: {test_case_file_path}")
        return test_case_file_path
    except Exception as e:
        app.logger.error(f"Error creating test case file: {str(e)}")
        raise

def run_pytest_and_generate_coverage(test_case_file_path):
    try:
        # 确保源代码文件和测试文件在同一目录
        source_file = test_case_file_path.replace('test_', '')
        if not os.path.exists(source_file):
            raise FileNotFoundError(f"Source file not found: {source_file}")

        # 运行pytest命令
        result = subprocess.run(
            ['pytest', '--cov', '.', '--cov-report', 'term-missing', test_case_file_path],
            cwd=app.config['UPLOAD_FOLDER'],
            capture_output=True,
            text=True
        )

        # 即使测试失败也保存输出
        coverage_report = result.stdout if result.stdout else "No coverage report generated"
        test_output = result.stderr if result.stderr else "No test output available"     
        # 记录详细的测试结果
        app.logger.info(f"Pytest return code: {result.returncode}")
        app.logger.info(f"Pytest stdout: {result.stdout}")
        app.logger.info(f"Pytest stderr: {result.stderr}")

        return coverage_report, test_output

    except Exception as e:
        app.logger.error(f"Error running pytest: {str(e)}")
        raise

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=6007)